﻿using BigEgg.Framework.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;

namespace FMStudio.Documents.Test
{
    [TestClass()]
    public class DocumentTypeTest
    {
        public string TestPath1 = Path.Combine(Environment.CurrentDirectory, "Test1.test");
        public string TestPath2 = Path.Combine(Environment.CurrentDirectory, "Test2.test");
        public string DataPath = Path.Combine(Environment.CurrentDirectory, "Data.data");

        [TestInitialize]
        public void TestCleanup()
        {
            if (File.Exists(TestPath1))
                File.Delete(TestPath1);

            if (File.Exists(TestPath2))
                File.Delete(TestPath2);

            if (File.Exists(DataPath))
                File.Delete(DataPath);
        }

        [TestMethod]
        public void ConstructorTest()
        {
            AssertHelper.ExpectedException<ArgumentException>(() => new MockDocumentTypeBase("", ".test"));
            AssertHelper.ExpectedException<ArgumentException>(() => new MockDocumentTypeBase("Test Documents", null));
            AssertHelper.ExpectedException<ArgumentException>(() => new MockDocumentTypeBase("Test Documents", "test"));
        }

        [TestMethod]
        public void CheckBaseImplementation()
        {
            MockDocumentTypeBase documentType = new MockDocumentTypeBase("Test Documents", ".test");
            Assert.IsFalse(documentType.CanNew());
            Assert.IsFalse(documentType.CanOpen());
            Assert.IsFalse(documentType.CanSave(null));

            AssertHelper.ExpectedException<ArgumentException>(() => documentType.New(""));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.New("abc:\"\\test.test"));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.Open(""));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.Open("test.test"));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.Open("abc:\"\\test.test"));
            CreateTestFile(DataPath);
            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.Open(DataPath));
            AssertHelper.ExpectedException<ArgumentNullException>(() => documentType.Save(null, "test.test"));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.Save(new MockDocumentBase(), ""));
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.Save(new MockDocumentBase(), "abc:\"\\test.test"));
            AssertHelper.ExpectedException<ArgumentNullException>(() => documentType.Save(null));

            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.New(TestPath1));
            AssertHelper.ExpectedException<FileNotFoundException>(() => documentType.Open(TestPath1));
            CreateTestFile(TestPath1);
            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.Open(TestPath1));
            AssertHelper.ExpectedException<NotSupportedException>(() =>
                documentType.Save(new MockDocumentBase(), TestPath1));

            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.CallNewCore(null));
            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.CallOpenCore(null));
            AssertHelper.ExpectedException<NotSupportedException>(() => documentType.CallSaveCore(null, null));
        }

        [TestMethod]
        public void NewDocumentTest()
        {
            MockDocumentType documentType = new MockDocumentType("Test Documents", ".test");
            Assert.IsTrue(documentType.CanNew());

            MockDocument document = documentType.New(TestPath2);
            Assert.AreEqual(TestPath2, documentType.FilePath);
            Assert.AreEqual(DocumentOperation.New, documentType.DocumentOperation);
            Assert.IsNotNull(document);

            Assert.AreEqual(TestPath2, document.FilePath);
            Assert.IsTrue(document.IsModified);

            //  File already exist
            CreateTestFile(TestPath1);
            AssertHelper.ExpectedException<ArgumentException>(() => documentType.New(TestPath1.Substring(0, TestPath1.Length - 5)));
        }

        [TestMethod]
        public void SaveDocumentTest()
        {
            MockDocumentType documentType = new MockDocumentType("Test Documents", ".test");
            MockDocument document = documentType.New(TestPath2);

            Assert.IsTrue(documentType.CanSave(document));
            document.IsModified = true;
            documentType.Save(document, TestPath1.Substring(0, TestPath1.Length - 5));
            Assert.AreEqual(TestPath1, documentType.FilePath);
            Assert.AreEqual(DocumentOperation.Save, documentType.DocumentOperation);
            Assert.IsNotNull(document);

            //  Save after modified
            document.IsModified = true;
            Assert.IsTrue(document.IsModified);
            documentType.Save(document, TestPath2);
            Assert.IsFalse(document.IsModified);
        }


        private void CreateTestFile(string filePath)
        {
            using (StreamWriter sw = new StreamWriter(filePath, false))
            {
                sw.Write("Test");
                sw.Close();
            }
        }


        private class MockDocumentTypeBase : DocumentType<MockDocumentBase>
        {
            public MockDocumentTypeBase(string description, string fileExtension)
                : base(description, fileExtension)
            {
            }

            public MockDocumentBase CallNewCore(string filePath) { return base.NewCore(filePath); }

            public MockDocumentBase CallOpenCore(string filePath) { return base.OpenCore(filePath); }

            public void CallSaveCore(MockDocumentBase document, string filePath) { base.SaveCore(document, filePath); }
        }

        private class MockDocumentBase : Document
        {
            public MockDocumentBase()
            {
            }
        }
    }
}
